package com.liuyu.common.framework.common.distribute;

/**
 * @ClassName RedissonLockUtil
 * @Author: liuyu
 * @Date: Created in 2020/11/10 12:47
 * @Version:
 * @Modified By:
 */

import com.liuyu.common.framework.common.utils.GlobalExecutorUtils;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.util.StringUtils;

import java.util.concurrent.TimeUnit;

/**
 * redis分布式锁帮助类
 *
 * @author 科帮网 By https://blog.52itstyle.com
 */
@Slf4j
public class RedissonLockUtils {
    private static RedissonClient redissonClient;

    private RedissonLockUtils() {

    }

    public static void setRedissonClient(RedissonClient redissonClient) {
        RedissonLockUtils.redissonClient = redissonClient;
    }

    /**
     * 加锁
     *
     * @param lockKey
     * @return
     */
    public static RLock lock(String lockKey) {
        RLock lock = redissonClient.getLock(lockKey);
        lock.lock();
        return lock;
    }

    /**
     * 释放锁
     *
     * @param lockKey
     */
    public static void unlock(String lockKey) {
        RLock lock = redissonClient.getLock(lockKey);
        lock.unlock();
    }

    /**
     * 释放锁
     *
     * @param lock
     */
    public static void unlock(RLock lock) {
        //判断锁是否存在，当前是否锁定，并且是否当前线程持有。
        if (lock != null && lock.isLocked() && lock.isHeldByCurrentThread()) {
            lock.unlock();
        }
    }

    /**
     * Redission释放锁
     *
     * @param lockKey 锁名
     */
    public static void unlockByKey(String lockKey) {
        RLock rLock = redissonClient.getLock(lockKey);
//        log.debug("[RedisLock][Rlock]>>>> {}, status: {} === unlock thread id is: {}", rLock.isHeldByCurrentThread(), rLock.isLocked(), Thread.currentThread().getId());
        if (rLock != null && rLock.isLocked() && rLock.isHeldByCurrentThread()) {
            if (log.isDebugEnabled()) {
                log.debug("锁：{}开始释放锁}", lockKey);
            }
            rLock.unlock();
        }
    }


    /**
     * 带超时的锁
     *
     * @param lockKey
     * @param timeout 超时时间   单位：秒
     */
    public static RLock lock(String lockKey, Integer timeout) {
        RLock lock = redissonClient.getLock(lockKey);
        lock.lock(timeout, TimeUnit.SECONDS);
        return lock;
    }

    /**
     * 带超时的锁
     *
     * @param lockKey
     * @param unit    时间单位
     * @param timeout 超时时间
     */
    public static RLock lock(String lockKey, TimeUnit unit, Integer timeout) {
        RLock lock = redissonClient.getLock(lockKey);
        lock.lock(timeout, unit);
        return lock;
    }

    /**
     * 尝试获取锁
     *
     * @param lockKey
     * @param waitTime  最多等待时间
     * @param leaseTime 上锁后自动释放锁时间
     * @return
     */
    public static boolean tryLock(String lockKey, Integer waitTime, Integer leaseTime) {
        RLock lock = redissonClient.getLock(lockKey);
        try {
            return lock.tryLock(waitTime, leaseTime, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            return false;
        }
    }

    /**
     * 尝试获取锁
     *
     * @param lockKey
     * @param unit      时间单位
     * @param waitTime  最多等待时间
     * @param leaseTime 上锁后自动释放锁时间
     * @return
     */
    public static boolean tryLock(String lockKey, TimeUnit unit, Integer waitTime, Integer leaseTime) {
        RLock lock = redissonClient.getLock(lockKey);
        try {
            return lock.tryLock(waitTime, leaseTime, unit);
        } catch (InterruptedException e) {
            return false;
        }
    }

    /**
     * Redission获取锁
     *
     * @param lockKey      锁名
     * @param uuid         唯一标识
     * @param delaySeconds 过期时间
     * @param unit         单位
     * @return 是否获取成功
     */
    public boolean Rlock(String lockKey, final String uuid, long delaySeconds, final TimeUnit unit) {
        RLock rLock = redissonClient.getLock(lockKey);
        boolean success = false;
        try {
            // log.debug("===lock thread id is :{}", Thread.currentThread().getId());
            success = rLock.tryLock(0, delaySeconds, unit);
        } catch (InterruptedException e) {
            log.error("[RedisLock][Rlock]>>>> 加锁异常: ", e);
        }
        return success;
    }

    /**
     * Redission释放锁
     *
     * @param lockKey 锁名
     */
    public void Runlock(String lockKey) {
        RLock rLock = redissonClient.getLock(lockKey);
        log.debug("[RedisLock][Rlock]>>>> {}, status: {} === unlock thread id is: {}", rLock.isHeldByCurrentThread(), rLock.isLocked(), Thread.currentThread().getId());
        rLock.unlock();
    }

    /**
     * Redission延迟释放锁
     *
     * @param lockKey   锁名
     * @param delayTime 延迟时间
     * @param unit      单位
     */
    public static void delayUnlock(final String lockKey, long delayTime, TimeUnit unit) {
        if (!StringUtils.hasText(lockKey)) {
            return;
        }
        if (log.isDebugEnabled()) {
            log.debug("锁：{}，延迟时间:{},时间单位:{}", lockKey, delayTime, unit.name());
        }
        if (delayTime <= 0) {
            unlockByKey(lockKey);
        } else {
            GlobalExecutorUtils.schedule(() -> unlockByKey(lockKey), delayTime, unit);
        }
    }
}
